// This file is licensed under the Elastic License 2.0. Copyright 2021-present, StarRocks Inc.

#include "io/fd_output_stream.h"

#include <fcntl.h>
#include <gtest/gtest.h>

#include "common/logging.h"
#include "testutil/assert.h"

namespace starrocks::io {

inline constexpr const char* kFileName = "FdOutputStreamTest.txt";

class FdOutputStreamTest : public ::testing::Test {
protected:
    void SetUp() override {
        int fd_w = open_for_write(kFileName);
        _out = std::make_unique<FdOutputStream>(fd_w);
    }

    void TearDown() override {
        _out.reset(nullptr);
        int r = ::unlink(kFileName);
        PLOG_IF(ERROR, r != 0) << "Fail to unlink " << kFileName;
    }

    int open_for_write(const char* path) {
        int fd = ::open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
        PLOG_IF(FATAL, fd < 0) << "Fail to open " << path << " for write";
        return fd;
    }

    int open_for_read(const char* path) {
        int fd = ::open(path, O_RDONLY);
        PLOG_IF(FATAL, fd < 0) << "Fail to open " << path << " for write";
        return fd;
    }

    std::string read_file(const char* path) {
        char buff[128];
        int nread;
        int fd = open_for_read(path);
        RETRY_ON_EINTR(nread, ::read(fd, buff, sizeof(buff)));
        (void)::close(fd);
        return std::string(buff, nread);
    }

private:
    std::unique_ptr<FdOutputStream> _out{};
};

TEST_F(FdOutputStreamTest, test_write) {
    std::string content("This file is generated by the unit test FdOutputStreamTest\n");
    ASSERT_OK(_out->write(content.data(), content.size()));
    ASSERT_OK(_out->close());
    _out.reset(nullptr);

    ASSERT_EQ(content, read_file(kFileName));
}

TEST_F(FdOutputStreamTest, test_write_and_sync) {
    std::string content("This file is generated by the unit test FdOutputStreamTest\n");
    _out->set_fdatasync_on_close(true);
    ASSERT_OK(_out->write(content.data(), content.size()));
    ASSERT_OK(_out->close());
    _out.reset(nullptr);

    ASSERT_EQ(content, read_file(kFileName));
}

TEST_F(FdOutputStreamTest, test_write_after_close) {
    ASSERT_OK(_out->close());
    ASSERT_FALSE(_out->write("abc", 3).ok());
}

TEST_F(FdOutputStreamTest, test_skip) {
    ASSERT_FALSE(_out->skip(12).ok());
}

} // namespace starrocks::io
